package com.zhaoshixin.es.service.impl;

import cn.hutool.core.date.DateUtil;
import com.zhaoshixin.es.entity.People;
import com.zhaoshixin.es.mapper.PeopleMapper;
import com.zhaoshixin.es.service.IPeopleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhaoshixin.es.vo.Query;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhaoshixin
 * @since 2022-07-26
 */
@Service
public class PeopleServiceImpl extends ServiceImpl<PeopleMapper, People> implements IPeopleService {
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Override
    public AggregatedPage getList(Query query, Integer pageNum, Integer pageSize) {
        //构造查询条件
        BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
        //如果查询的姓名不为null也不为""的时候
        if(query.getName()!=null && !"".equals(query.getName())){
            //姓名查询
            queryBuilder.must(QueryBuilders.multiMatchQuery(query.getName(),"name"));
        }
        //如果开始时间和结束时间都为null是进行构造日期区间查询
        if(query.getStart()!=null && query.getEnd()!=null){
            //生日区间查询
            queryBuilder
                    .must(QueryBuilders.rangeQuery("birthday")
                    .gte(DateUtil.format(query.getStart(),"yyyy-MM-dd"))
                    .lte(DateUtil.format(query.getEnd(),"yyyy-MM-dd")));
        }

        //构造高亮字段
        HighlightBuilder.Field field = new HighlightBuilder.Field("name")
                .preTags("<span style='color:red;'>")
                .postTags("</span>");
        //构造searchQuery 包含查询条件,高亮字段,分页
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                // 索引名称
                .withIndices("es_demo")
                // 类型
                .withTypes("people")
                // 构造的查询条件
                .withQuery(queryBuilder)
                //构造的高亮字段
                .withHighlightFields(field)
                // 分页
                .withPageable(PageRequest.of(pageNum - 1, pageSize, Sort.Direction.ASC,"id"))
                .build();
        //封装结果集
        AggregatedPage<People> aggregatedPage = elasticsearchTemplate.queryForPage(searchQuery, People.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                //获取查询到的所有数据
                SearchHit[] hits = response.getHits().getHits();
                //这个集合用来保存查询到的数据
                ArrayList<People> peoples = new ArrayList<>();
                //遍历每一个对象
                for (SearchHit hit : hits) {
                    //获取map
                    Map<String, Object> map = hit.getSourceAsMap();
                    //先给map集合添加一个id
                    map.put("id",hit.getId());
                    // 获取高亮查询的结果
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    // 遍历map集合
                    for (Map.Entry<String, Object> entry : map.entrySet()) {
                        // 查看是否满足高亮字段的key
                        HighlightField highlightField = highlightFields.get(entry.getKey());
                        //如果不为空 证明这个字段为高亮字段
                        if(highlightField!=null){
                            // 进行赋值操作
                            map.put(entry.getKey(),highlightField.fragments()[0].toString());
                        }
                    }
                    //封装返回的对象数据
                    People people = new People();
                    people.setId(Integer.parseInt(map.get("id").toString()));
                    people.setAge(Integer.parseInt(map.get("age").toString()));
                    people.setName(map.get("name").toString());
                    people.setBirthday(DateUtil.parse(map.get("birthday").toString()));
                    // 添加到我们定义的集合中
                    peoples.add(people);
                }
                //最后进行返回
                return new AggregatedPageImpl(peoples,pageable,response.getHits().totalHits);
            }

            @Override
            public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
                return null;
            }
        });

        return aggregatedPage;
    }
}
